package gui;

import domain.GameGrid;
import domain.player.Player;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import main.AppConstants;

/**
 * The GameFrame is the main component of the game. GameFrame fires up upon
 * application start. It shows a splash image and let the client start a new
 * game by calling SetupGameDialog or quit the application.
 *
 * When a game has started GameFrame contains the board component (GameBoard).
 */
public class GameFrame extends JFrame {

	private GUIController guiController;
	private JPanel playerPanel;
	private JPanel boardPanel;
	private JLabel currentPlayerDisc;
	private JLabel currentPlayerLabel;
	private final Font fontPlayerName = new Font(Font.DIALOG, Font.BOLD, 12);
	private JLabel startImage = new JLabel();
	private final ImageIcon startIcon = new ImageIcon(getClass().getClassLoader().getResource(AppConstants.IMAGE_SPLASH));
	private Container content = getContentPane();

	public GameFrame(GUIController gameController) {
		this.guiController = gameController;

		javax.swing.SwingUtilities.invokeLater(new Runnable() {

			@Override
			public void run() {
				createGameFrame();
			}
		});
	}

	/** Update the JLabel with the current player */
	public void updateCurrentPlayer(Player player) {
		currentPlayerLabel.setText(player.getName());
		currentPlayerDisc.setIcon(new DiscIcon(player.getDiscColor(), 0.3));
	}

	/** Create the game frame */
	private void createGameFrame() {
		// Use current system look and feel:
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			SwingUtilities.updateComponentTreeUI(this);
		} catch (Exception e) {
			System.out.println(e.toString());
		}

		setIconImage(new ImageIcon(getClass().getClassLoader().getResource(AppConstants.IMAGE_APP_ICON)).getImage());

		setTitle(AppConstants.GAME_FRAME_TITLE_APP);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		// Add the splash image:
		startImage.setIcon(startIcon);
		content.add(startImage, BorderLayout.CENTER);
		addButtons();

		updateGameFrame();
		setVisible(true);
		setResizable(false);
	}

	/** Add new and quit buttons to the frame */
	private void addButtons() {
		JPanel buttonPanel = new JPanel();
		buttonPanel.setBackground(AppConstants.COLOR_PANEL_BACKGROUND);

		JButton jBtnNew = new JButton("New Game");
		jBtnNew.setBackground(AppConstants.COLOR_PANEL_BACKGROUND);
		jBtnNew.addActionListener(new NewGameListener());
		buttonPanel.add(jBtnNew);

		JButton jBtnCustom = new JButton("Customized Game");
		jBtnCustom.setBackground(AppConstants.COLOR_PANEL_BACKGROUND);
		jBtnCustom.addActionListener(new CustomGameListener());
		buttonPanel.add(jBtnCustom);

		JButton jBtnQuit = new JButton("Quit");
		jBtnQuit.setBackground(AppConstants.COLOR_PANEL_BACKGROUND);
		jBtnQuit.addActionListener(new QuitListener());
		buttonPanel.add(jBtnQuit);
		buttonPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0,
				AppConstants.COLOR_PANEL_BORDER));

		content.add(buttonPanel, BorderLayout.SOUTH);
	}

	/** Add a JPanel for the current player's name to the frame */
	private JPanel createPlayerPanel() {
		if (playerPanel == null) {
			playerPanel = new JPanel(new FlowLayout());
			playerPanel.setBackground(AppConstants.COLOR_PANEL_BACKGROUND);

			// Current player:
			JLabel curPlayerLabel = new JLabel("Current player:");
			curPlayerLabel.setForeground(AppConstants.COLOR_PANEL_FOREGROUND);
			playerPanel.add(curPlayerLabel);

			// Player's disc:
			currentPlayerDisc = new JLabel();
			playerPanel.add(currentPlayerDisc);

			// Player's name:
			currentPlayerLabel = new JLabel();
			currentPlayerLabel.setFont(fontPlayerName);
			currentPlayerLabel.setForeground(AppConstants.COLOR_PANEL_FOREGROUND);
			playerPanel.add(currentPlayerLabel);

			playerPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0,
					AppConstants.COLOR_PANEL_BORDER));
		}
		return playerPanel;
	}

	/** Adds the game board to the frame */
	private JPanel getGameBoard() {
		int boardWidth = GameGrid.GRID_COLUMNS * 80;
		int boardHeight = GameGrid.GRID_ROWS * 80 - (boardPanel != null ? 10 : 0);

		// Remove the old boardPanel:
		if (boardPanel != null) {
			remove(boardPanel);
		}

		// Get the game board and set its dimensions:
		boardPanel = guiController.getGameBoardPanel();
		boardPanel.setSize(new Dimension(boardWidth, boardHeight));
		boardPanel.setPreferredSize(new Dimension(boardWidth, boardHeight));

		return boardPanel;
	}

	/** Updates the game frame */
	public void updateGameFrame() {
		pack();
		setLocationRelativeTo(null);
		repaint();
	}

	/** Adds a menu bar with options for changing the AI of a computer controlled player. */
	private JMenuBar GameFrameMenuBar(){
		JMenuBar jmnBar = new JMenuBar();
		JMenu menuAI =  new JMenu("AI Settings");

		JMenuItem jmniAI = new JMenuItem("Change Computer AI");
		jmniAI.addActionListener(new AISettingsListener());
		menuAI.add(jmniAI);

                JMenuItem jmniAID = new JMenuItem("Enter Debug");
		jmniAID.addActionListener(new DebugListener());
		menuAI.add(jmniAID);



                /*JMenuItem jmniSetBoard = new JMenuItem("setboard old");
		jmniSetBoard.addActionListener(new SetBoardListener());
		menuAI.add(jmniSetBoard);*/

		jmnBar.add(menuAI);
		return jmnBar;
	}

	/** Creates a new game board */
	private void newGameBoard() {
		SetupGameDialog setupGameDialog = new SetupGameDialog(
				guiController.getPlayer(1), guiController.getPlayer(2)
		);
		Player player1 = setupGameDialog.getPlayer(1);
		Player player2 = setupGameDialog.getPlayer(2);

		if (player1 != null && player2 != null) {
			// Remove start image:
			if (startImage != null) {
				remove(startImage);
			}
			guiController.resetGame();
			guiController.addPlayers(player1, player2);

			// Add player panel:
			content.add(createPlayerPanel(), BorderLayout.NORTH);

			// Add game board:
			boardPanel = getGameBoard();
			content.add(boardPanel, BorderLayout.CENTER);

			// Update the game frame:
			updateGameFrame();

			// Start the game:
			guiController.startGame();
		}
	}

	/** Creates a new game board */
	private void customizedGameBoard() {
		SetupGameDialog setupGameDialog = new SetupGameDialog(
				guiController.getPlayer(1), guiController.getPlayer(2)
		);
		Player player1 = setupGameDialog.getPlayer(1);
		Player player2 = setupGameDialog.getPlayer(2);

		if (player1 != null && player2 != null) {
			// Remove start image:
			if (startImage != null) {
				remove(startImage);
			}

			guiController.resetGameBoard();
			guiController.addPlayers(player1, player2);

			// Add player panel:
			content.add(createPlayerPanel(), BorderLayout.NORTH);

			// Add game board:
			boardPanel = getGameBoard();
			content.add(boardPanel, BorderLayout.CENTER);

			// Update the game frame:
			guiController.getGameBoardPanel().updateGameBoard();
			updateGameFrame();

			// Start the game:
			guiController.startGame();
		}
	}

	/** Button listener: New Game */
	private class NewGameListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			setJMenuBar(GameFrameMenuBar());
			newGameBoard();
		}
	}

	/** Button listener: Customize Game */
	private class CustomGameListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			setJMenuBar(GameFrameMenuBar());
			System.out.println("setting board");

			new SetDialog(guiController.getLogicController());

			System.out.println(guiController.getLogicController().getGameGrid().toString());
			customizedGameBoard();
		}
	}

	/** Button listener: Quit */
	private class QuitListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			guiController.quitGame();
			for (Frame frameEle : Frame.getFrames()) {
				frameEle.dispose();
			}
			System.exit(0);
		}
	}

	/** Button listener: AI settings */
	private class AISettingsListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent ae) {
			new SetupAIDialog(guiController.getPlayer(0), guiController.getPlayer(1));
		}
	}

        /** Button listener: Debug */
	private class DebugListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent ae) {
                    System.out.println("entering debug");
                    guiController.setDebug(true);
		}
	}

         /** Button listener: SetBoard */
	private class SetBoardListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent ae) {
                    System.out.println("setting board");
                    guiController.presentSetBoardDialog();
		}
	}
}
